package com.spzx.product;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spzx.common.security.annotation.EnableCustomConfig;
import com.spzx.common.security.annotation.EnableRyFeignClients;

import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.service.IProductSkuService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;

/**
 * @author GAX
 * @date 2025-08-22
 */

@EnableCustomConfig
@EnableRyFeignClients
@SpringBootApplication
@Slf4j
public class SpzxProductApplication implements CommandLineRunner, ApplicationRunner {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IProductSkuService productSkuService;

    public static void main(String[] args) {
        // 启动 Spring Boot 应用。
        // Spring 会开始初始化 IoC 容器，创建和装配所有的 Bean。
        SpringApplication.run(SpzxProductApplication.class, args);
        log.info("========== Spring Boot 应用启动完成 ==========");
    }

    /**
     * ApplicationRunner 接口的 run 方法。
     * - 执行时机：在整个 Spring 应用完全启动之后，CommandLineRunner 之前。
     * - 作    用：用于执行应用级别的启动任务，例如缓存预热、加载初始化数据等。
     * - 特    点：参数 ApplicationArguments 是对命令行参数的封装，更易于使用。
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunner...... run(ApplicationArguments args) 执行");
    }

    /**
     * CommandLineRunner 接口的 run 方法。
     * - 执行时机：在整个 Spring 应用完全启动之后，ApplicationRunner 之后。
     * - 作    用：与 ApplicationRunner 作用相同。
     * - 特    点：参数 String... args 是最原始的命令行参数数组。
     */
    @Override
    public void run(String... args) throws Exception {
        log.info("CommandLineRunner...... run(String... args) 执行");
        String redisBitMapKey = "product:sku:data";
        // 查询所有上架商品 ID，并且加入到 Redis 的 bitmap 位图
        List<ProductSku> productSkuList = productSkuService.list(new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getStatus, 1));

        // 遍历出商品 sku 对象，将对象中 ID 作为 offset 偏移量，置该处偏移量的 bit 值为 1
        productSkuList.forEach(elm -> {
            redisTemplate.opsForValue().setBit(redisBitMapKey,elm.getId(),true);
        });
    }

    /**
     * JSR-250 标准注解，用于标记一个 Bean 的初始化方法。
     * - 执行时机：在当前 Bean (SpzxProductApplication) 的构造方法执行完毕、
     * 所有依赖注入（@Autowired）完成后，被立刻调用。
     * -           它的执行远早于 ApplicationRunner 和 CommandLineRunner。
     * - 作    用：执行依赖于注入资源（Bean）的初始化操作。
     */
    @PostConstruct
    public void init() {
        log.info("PostConstruct init...... 方法执行");
    }
}